package com.shortlink.gateway.filter;

import cn.hutool.core.util.ObjectUtil;
import com.shortlink.common.base.Result;
import com.shortlink.common.base.Results;
import com.shortlink.common.base.errcode.AuthErrorCode;
import com.shortlink.common.constant.HeaderConstant;
import com.shortlink.common.exception.RemoteException;
import com.shortlink.common.user.UserInfoDTO;
import com.shortlink.gateway.config.AuthFilterProperties;
import com.shortlink.gateway.remote.AuthRemoteService;
import com.shortlink.gateway.util.FilterUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Optional;

/**
 * 权限认证拦截器
 *
 * @author wp
 */
@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter {
    @Resource
    @Lazy
    private AuthRemoteService authRemoteService;
    @Resource
    private AuthFilterProperties authFilterProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestPath = request.getPath().toString();
        if (!authFilterProperties.isInWhite(requestPath)) {
            String token = request.getHeaders().getFirst(HeaderConstant.AUTHORIZATION);
            Result<UserInfoDTO> result;
            try {
                result = authRemoteService.auth(token, requestPath);
            } catch (Exception e) {
                return FilterUtils.returnJson(exchange, Results.failure(new RemoteException(e.getMessage())));
            }
            if (!result.isSuccess()) {
                if (AuthErrorCode.NO_AUTH.code().equals(result.getCode())) {
                    //权限错误直接返回result
                    return FilterUtils.returnJson(exchange, result);
                }
                Result<Void> errResult = Results.failure(new RemoteException(result.getMessage()));
                return FilterUtils.returnJson(exchange, errResult);
            }
            //设置用户信息请求头
            UserInfoDTO userInfoDTO = result.getData();
            log.info(String.format("token(%s) userInfo(%s) request(%s)", token, userInfoDTO, requestPath));
            if (ObjectUtil.isNotEmpty(userInfoDTO)) {
                request = request.mutate()
                        .header(HeaderConstant.USER_ID, Optional.ofNullable(userInfoDTO.getUserId()).map(String::valueOf).orElse(null))
                        .header(HeaderConstant.USERNAME, userInfoDTO.getUsername())
                        .header(HeaderConstant.USER_GROUP_NAME, userInfoDTO.getGroupName())
                        .header(HeaderConstant.USER_GROUP_LEVEL, Optional.ofNullable(userInfoDTO.getGroupLevel()).map(String::valueOf).orElse(null))
                        .build();
            }

            exchange = exchange.mutate().request(request).build();
        }
        return chain.filter(exchange);
    }
}
